/*
 * Copyright 2011 The Rusted Roof, LLC.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package org.proteusframework.platformservice;

import org.proteusframework.core.api.IPlatformDelegate;
import org.proteusframework.core.api.config.IConfiguration;
import org.proteusframework.core.api.model.INamespace;
import org.proteusframework.core.api.model.IPlugin;
import org.proteusframework.platformservice.appconfig.IAppConfigService;
import org.proteusframework.platformservice.lifecycle.api.ILifecycleService;
import org.proteusframework.platformservice.messaging.IMessageService;
import org.proteusframework.platformservice.persistence.api.IPersistenceService;
import org.proteusframework.platformservice.theme.IThemeService;

/**
 * Specialized type of an {@link org.proteusframework.core.api.IPlatformDelegate} that depicts a platform service
 * delegate. Platform service delegates expressly provide application-wide service access that is
 * intrinsically integrated into the Proteus Framework itself.
 *
 * @see IServicePlugin
 */
public interface IExtendedPlatformDelegate extends IPlatformDelegate, IScopedServiceDelegate
{
    /**
     * Obtains the configuration interface for the given configurable service plugin.
     *
     * @param serviceInterface Service interface
     * @param <T>              Specific type of service interface
     * @return Non-null IConfiguration instance for the given service
     */
    <T extends IServicePlugin> IConfiguration getServiceConfiguration(Class<T> serviceInterface);

    /**
     * Obtains the configuration interface for the given custom ({@link ServiceClassification#Custom}) configurable
     * service plugin.
     *
     * @param namespace        Alternative namespace under which the platform service was registered.
     * @param serviceInterface Custom service interface
     * @param <T>              Specific type of service interface
     * @return Non-null IConfiguration instance for the given service
     * @throws ServiceNotInstalledException When the custom service is not presently installed in the application
     */
    <T extends IServicePlugin> IConfiguration getServiceConfiguration(INamespace namespace,
                                                                      Class<T> serviceInterface)
            throws ServiceNotInstalledException;

    /**
     * Request the active primordial instance of the specified platform service, if the service is installed in the
     * given runtime environment.
     *
     * @param expectedInterface Expected interface of the given platform service
     * @return Active instance of the specified platform service
     * @throws ServiceNotInstalledException when no matching service can be found
     */
    <T extends IServicePlugin> T getPlatformService(Class<T> expectedInterface) throws ServiceNotInstalledException;

    /**
     * Request a specific {@link ServiceClassification} service. When {@link ServiceClassification#Persistence} is
     * specified, the primordial persistence service is request, if installed. To access secondary persistence
     * services, specify <code>ServiceClassification.Custom</code> as the service classification.
     *
     * @param serviceClassification Service classification
     * @param expectedInterface     Expected interface
     * @return Active instance of the specified service classification.
     * @throws ServiceNotInstalledException when the expected interface for the specific service classification is
     *                                      not installed
     */
    <T extends IServicePlugin> T getPlatformService(ServiceClassification serviceClassification, Class<T> expectedInterface)
            throws ServiceNotInstalledException;

    /**
     * Requests a {@link ServiceClassification#Custom} service associated with the given <code>INamespace</code>. This
     * routine is typically used to access secondary persistence or theme services.
     *
     * @param expectedInterface Expteced interface of the given platform service
     * @param namespace         Alternative namespace under which the platform service was registered.
     * @return Active instance of the specified platform service
     * @throws ServiceNotInstalledException when no matching service can be found
     */
    <T extends IServicePlugin> T getPlatformService(INamespace namespace, Class<T> expectedInterface)
            throws ServiceNotInstalledException;

    /**
     * Convenience method for <code>getPlatformService(IAppConfigService.class)</code>. Since Proteus Platform
     * Services work with exactly one <code>IAppConfigService</code> instance that cannot be dynamically switched
     * during the application's lifeline, it is safe for callers to cache the returned service.
     *
     * @return Cache-friendly app config service
     * @throws org.proteusframework.core.util.AssertionFailedException
     *          when the Proteus Platform Services are not available
     */
    IAppConfigService getAppConfigService();

    /**
     * Convenience method for <code>getPlatformService(ILifecycleService.class)</code>. Since Proteus Platform
     * Services work with exactly one <code>ILifecycleService</code> instance that cannot be dynamically switched
     * during the application's lifeline, it is safe for callers to cache the returned service.
     *
     * @return Cache-friendly lifecycle service
     * @throws org.proteusframework.core.util.AssertionFailedException
     *          when the Proteus Platform Services are not available
     */
    ILifecycleService getLifecycleService();

    /**
     * Convenience method for determining if the application registered any theme service instances.
     *
     * @return true, if a theme service was installed and is available
     */
    boolean isThemeServiceAvailable();

    /**
     * Convenience method for <code>getPlatformService(IThemeService.class)</code>. Since Proteus Platform
     * Services may work with zero, one, or many <code>IThemeService</code> instances that can be dynamically switched
     * during the application's lifeline, it is <i>not safe</i> for callers to cache the returned service.
     *
     * @return Theme service that is <b>unsafe for caching</b>
     * @throws org.proteusframework.core.util.AssertionFailedException
     *          when the Proteus Platform Services are not available
     */
    IThemeService getThemeService();

    /**
     * Convenience method for determining if the application registered a primordial persistence service instance.
     *
     * @return true, if a primordial persistence service was installed and is available
     */
    boolean isPersistenceServiceAvailable();

    /**
     * Convenience method for <code>getPlatformService(IPersistenceService.class)</code>. Since Proteus Platform
     * Services work with exactly zero, one, or many <code>IPersistenceService</code> instances that can be dynamically
     * switched during the application's lifeline, it is <i>not safe</i> for callers to cache the returned service, even
     * though this method returns only the primordial persistence service (if installed).
     *
     * @return Primordial persistence service that is <b>unsafe for caching</b>
     * @throws org.proteusframework.core.util.AssertionFailedException
     *          when the Proteus Platform Services are not available
     */
    IPersistenceService getPersistenceService();

    /**
     * Convenience method for determining if the application registered a primordial message service instance.
     *
     * @return true, if a primordial message service was installed and is available
     */
    boolean isMessageServiceAvailable();

    /**
     * Convenience method for <code>getPlatformService(IMessageService.class)</code>. Since Proteus Platform
     * Services work with exactly zero, one, or many <code>IMessageService</code> instances that can be dynamically
     * switched during the application's lifeline, it is <i>not safe</i> for callers to cache the returned service, even
     * though this method returns only the primordial message service (if installed).
     *
     * @return Primordial persistence service that is <b>unsafe for caching</b>
     * @throws org.proteusframework.core.util.AssertionFailedException
     *          when the Proteus Platform Services are not available
     */
    IMessageService getMessageService();
}
